package com.agileai.hotweb.bizmoduler.core;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.agileai.common.KeyGenerator;
import com.agileai.domain.DataParam;
import com.agileai.domain.DataRow;
import com.agileai.domain.db.Column;
import com.agileai.domain.db.Table;
import com.agileai.hotweb.common.Constants;
import com.agileai.hotweb.domain.TreeModel;
import com.agileai.util.ListUtil;
import com.agileai.util.StringUtil;

public class TreeAndContentManageImpl extends BaseService implements
		TreeAndContentManage {
	public static final String PRIMARY_KEY = "primaryKey";
	public static final String PK_GEN_POLICY = "pkGenPolicy";
	
	public static final class TableMode{
		public static final String One2Many = "One2Many";
		public static final String Many2ManyAndRel = "Many2ManyAndRel";
	}	

	protected String columnIdField = "INFOCOL_ID";
	protected String columnParentIdField = "INFOCOL_PID";
	protected String columnSortField = "INFOCOL_ORDERNO";	
	
	protected Map<String,String> tabIdAndTableNameMapping = new HashMap<String,String>();
	protected Map<String,String> tabIdAndColFieldMapping = new HashMap<String,String>();
	protected Map<String,String> tabIdAndTableModeMapping = new HashMap<String,String>();
	
	protected HashMap<String,HashMap<String,String>> tableNamePersistenceInfoMapping = new HashMap<String,HashMap<String,String>>();
	
	public TreeAndContentManageImpl() {
        super();
    }
	
	private String getPrimaryKey(String tableName){
		String result = null; 
		HashMap<String,String> persistenceInfo = tableNamePersistenceInfoMapping.get(tableName);
		result = persistenceInfo.get(PRIMARY_KEY);
		return result;
	}
	private String getPkGenPolicy(String tableName){
		String result = null; 
		HashMap<String,String> persistenceInfo = tableNamePersistenceInfoMapping.get(tableName);
		result = persistenceInfo.get(PK_GEN_POLICY);
		return result;
	}
	
	public void createtContentRecord(String tabId,DataParam param) {
		String statementId = sqlNameSpace+"."+"insert"+StringUtil.upperFirst(tabId)+"Record";
		String curTableName = tabIdAndTableNameMapping.get(tabId);
		processDataType(param, curTableName);
		processPrimaryKeys(curTableName,param);
		this.daoHelper.insertRecord(statementId, param);
		String tableMode = tabIdAndTableModeMapping.get(tabId);
		if (TableMode.Many2ManyAndRel.equals(tableMode)){
			statementId = sqlNameSpace+"."+"insert"+StringUtil.upperFirst(tabId)+"Relation";
			this.daoHelper.insertRecord(statementId, param);			
		}
	}
	
	public void createtContentRecord(String tabId,DataParam param, String pKeyValue) {
		String statementId = sqlNameSpace+"."+"insert"+StringUtil.upperFirst(tabId)+"Record";
		String curTableName = tabIdAndTableNameMapping.get(tabId);
		processDataType(param, curTableName);
		param.put(getPrimaryKey(curTableName),pKeyValue);
		this.daoHelper.insertRecord(statementId, param);
		
		String tableMode = tabIdAndTableModeMapping.get(tabId);
		if (TableMode.Many2ManyAndRel.equals(tableMode)){
			statementId = sqlNameSpace+"."+"insert"+StringUtil.upperFirst(tabId)+"Relation";
			this.daoHelper.insertRecord(statementId, param);
		}
	}

	public void insertTreeContentRelation(String tabId, DataParam param) {
		String statementId = sqlNameSpace+"."+"insert"+StringUtil.upperFirst(tabId)+"Relation";
		this.daoHelper.insertRecord(statementId, param);
	}

	public void updateTreeContentRelation(String tabId, DataParam param) {
		String statementId = sqlNameSpace+"."+"update"+StringUtil.upperFirst(tabId)+"Relation";
		this.daoHelper.updateRecord(statementId, param);
	}	

	public boolean isLastTreeContentRelation(String tabId, DataParam param) {
		boolean result = false;
		String statementId = sqlNameSpace+"."+"query"+StringUtil.upperFirst(tabId)+"Relation";
		List<DataRow> tempRecords = this.daoHelper.queryRecords(statementId, param);
		if (ListUtil.isNullOrEmpty(tempRecords) || tempRecords.size()==1){
			result = true;
		}
		return result;
	}

	public void removeTreeContentRelation(String tabId, DataParam param) {
		String statementId = sqlNameSpace+"."+"delete"+StringUtil.upperFirst(tabId)+"Relation";
		this.daoHelper.deleteRecords(statementId, param);
	}	
	
	public DataRow getContentRecord(String tabId,DataParam param) {
		String statementId = sqlNameSpace+"."+"get"+StringUtil.upperFirst(tabId)+"Record";
		DataRow result = this.daoHelper.getRecord(statementId, param);
		return result;
	}
	public void updatetContentRecord(String tabId,DataParam param) {
		String statementId = sqlNameSpace+"."+"update"+StringUtil.upperFirst(tabId)+"Record";
		String curTableName = tabIdAndTableNameMapping.get(tabId);
		processDataType(param, curTableName);
		this.daoHelper.updateRecord(statementId, param);
	}
	public void deletContentRecord(String tabId,DataParam param) {
		String statementId = sqlNameSpace+"."+"delete"+StringUtil.upperFirst(tabId)+"Record";
		this.daoHelper.deleteRecords(statementId, param);
		
		String tableMode = tabIdAndTableModeMapping.get(tabId);
		if (TableMode.Many2ManyAndRel.equals(tableMode)){
			statementId = sqlNameSpace+"."+"delete"+StringUtil.upperFirst(tabId)+"Relation";
			this.daoHelper.deleteRecords(statementId, param);
		}
	}
	public List<DataRow> findContentRecords(TreeModel treeModel,String tabId,DataParam param) {
		List<DataRow> result = null;
		String statementId = sqlNameSpace+"."+"find"+StringUtil.upperFirst(tabId)+"Records";
		
		DataParam newParam = new DataParam();
		newParam.append(param);
		boolean showChildNodeRecords = "Y".equals(param.get("showChildNodeRecords")); 
		if (showChildNodeRecords){
			newParam.remove("columnId");
		}
		result = this.daoHelper.queryRecords(statementId, newParam);
		if (result != null && showChildNodeRecords){
			Map<String,TreeModel> childrenMap = treeModel.getChildrenMap();
			String columnIdField = this.tabIdAndColFieldMapping.get(tabId);
			List<DataRow> temp = new ArrayList<DataRow>();
			for (int i=0;i < result.size();i++){
				DataRow row = result.get(i);
				String columnId = row.stringValue(columnIdField);
				if (columnId.equals(treeModel.getId()) || childrenMap.containsKey(columnId)){
					temp.add(row);
				}
			}
			result = temp;
		}
		return result;
	}
	
	protected void processPrimaryKeys(String tableName,DataParam param){
		String primaryKey = getPrimaryKey(tableName);
		String pkGenPolicy = getPkGenPolicy(tableName);
		KeyGenerator keyGenerator = new KeyGenerator();
		if (Constants.PKType.INCREASE.equals(pkGenPolicy)){
			param.put(primaryKey,keyGenerator.getMaxId(tableName, primaryKey,getDataSource()));
		}
		else if(Constants.PKType.CHARGEN.equals(pkGenPolicy)){
			String genPk = keyGenerator.genKey();
			param.put(primaryKey,genPk);
		}
	}
	protected void processDataType(DataParam dataParam,String tableName){
		super.processDataType(dataParam, tableName);
		if (!tableNamePersistenceInfoMapping.containsKey(tableName)){
			Table table = getTableMetaData(tableName);
			List<Column> columns = table.getColumns();
			HashMap<String,String> persistenceInfo = new HashMap<String,String>();
			String primaryKey = null;
			int count = columns.size();
			for (int i=0;i < count;i++){
				Column column = columns.get(i);
				if (column.isPK()){
					primaryKey = column.getName();
					persistenceInfo.put(PRIMARY_KEY, primaryKey);
					break;
				}
			}
			String pkGenPolicy = null;
			for (int i=0;i < count;i++){
				Column column = columns.get(i);
				if (primaryKey != null
						&& primaryKey.equals(column.getName())){
					if ("java.lang.Integer".equals(column.getClassName())
							|| "java.lang.Long".equals(column.getClassName())){
						pkGenPolicy = Constants.PKType.INCREASE;
						break;
					}
					else if ("java.lang.String".equals(column.getClassName())){
						if (column.getLength()%36 == 0 && column.getLength() < 150){
							pkGenPolicy = Constants.PKType.CHARGEN;
							break;
						}
						else{
							pkGenPolicy = Constants.PKType.ASSIGN;
							break;
						}
					}
				}
			}
			persistenceInfo.put(PK_GEN_POLICY, pkGenPolicy);
			tableNamePersistenceInfoMapping.put(tableName, persistenceInfo);
		}
	}	

	public List<DataRow> findTreeRecords(DataParam param) {
		String statementId = this.sqlNameSpace+"."+"queryTreeRecords";
		return this.daoHelper.queryRecords(statementId, param);
	}

	public DataRow queryTreeRecord(DataParam param) {
		String statementId = this.sqlNameSpace+"."+"queryTreeRecord";
		return this.daoHelper.getRecord(statementId, param);
	}

	public void createTreeRecord(DataParam param) {
		String statementId = sqlNameSpace+"."+"insertTreeRecord";
		processDataType(param, tableName);
		processPrimaryKeys(tableName,param);
		String parentId = param.get(columnParentIdField);
		String newSort = String.valueOf(this.retrieveNewMaxSort(parentId));
		param.put(columnSortField,newSort);
		this.daoHelper.insertRecord(statementId, param);
	}
	
	public void createTreeRecord(DataParam param, String pKeyValue) {
		String statementId = sqlNameSpace+"."+"insertTreeRecord";
		processDataType(param, tableName);
		param.put(getPrimaryKey(tableName),pKeyValue);
		String parentId = param.get(columnParentIdField);
		String newSort = String.valueOf(this.retrieveNewMaxSort(parentId));
		param.put(columnSortField,newSort);
		this.daoHelper.insertRecord(statementId, param);
	}	
	public void updateTreeRecord(DataParam param) {
		String statementId = sqlNameSpace+"."+"updateTreeRecord";
		processDataType(param, tableName);
		this.daoHelper.updateRecord(statementId, param);
	}		

	public void deleteTreeRecord(String currentId) {
		String statementId = sqlNameSpace+"."+"deleteTreeRecord";
		this.daoHelper.deleteRecords(statementId, currentId);
	}

	public List<DataRow> queryChildTreeRecords(String currentId) {
		String statementId = this.sqlNameSpace+"."+"queryChildTreeRecords";
		return this.daoHelper.queryRecords(statementId, currentId);
	}
	
	public void changeTreeSort(String currentId, boolean isUp) {
		String statementId = this.sqlNameSpace+"."+"queryCurLevelRecords";
		List<DataRow> records = this.daoHelper.queryRecords(statementId, currentId);
		DataRow curRow = null;
		String curSort = null;
		if (isUp){
			DataRow beforeRow = null;
			for (int i=0;i < records.size();i++){
				DataRow row = records.get(i);
				String tempMenuId = row.stringValue(columnIdField);
				if (currentId.equals(tempMenuId)){
					curRow = row;
					beforeRow = records.get(i-1);
					break;
				}
			}
			curSort = curRow.stringValue(columnSortField);
			String beforeSort = beforeRow.stringValue(columnSortField);;
			curRow.put(columnSortField,beforeSort);
			beforeRow.put(columnSortField,curSort);
			this.updateTreeRecord(curRow.toDataParam());
			this.updateTreeRecord(beforeRow.toDataParam());
		}else{
			DataRow nextRow = null;
			for (int i=0;i < records.size();i++){
				DataRow row = records.get(i);
				String tempMenuId = row.stringValue(columnIdField);
				if (currentId.equals(tempMenuId)){
					curRow = row;
					nextRow = records.get(i+1);
					break;
				}
			}
			curSort = curRow.stringValue(columnSortField);
			String nextSort = nextRow.stringValue(columnSortField);
			curRow.put(columnSortField,nextSort);
			nextRow.put(columnSortField,curSort);
			this.updateTreeRecord(curRow.toDataParam());
			this.updateTreeRecord(nextRow.toDataParam());
		}
	}

	public int retrieveNewMaxSort(String parentId){
		int result = 0;
		String statementId = this.sqlNameSpace+"."+"queryMaxSortId";
		DataRow row = this.daoHelper.getRecord(statementId, parentId);
		String maxMenuSort = row.stringValue("MAX_"+columnSortField);
		if (!StringUtil.isNullOrEmpty(maxMenuSort)){
			result = Integer.parseInt(maxMenuSort)+1;
		}else{
			result =1;
		}
		return result;
	}
	
	public boolean isFirstTreeChild(String currentId) {
		boolean result = false;
		String statementId = this.sqlNameSpace+"."+"queryCurLevelRecords";
		List<DataRow> records = this.daoHelper.queryRecords(statementId, currentId);
		if (!ListUtil.isNullOrEmpty(records)){
			DataRow firstRow = records.get(0);
			String tempMenuId = firstRow.stringValue(columnIdField);
			if (currentId.equals(tempMenuId)){
				result = true;
			}
		}
		return result;
	}

	public boolean isLastTreeChild(String currentId) {
		boolean result = false;
		String statementId = this.sqlNameSpace+"."+"queryCurLevelRecords";
		List<DataRow> records = this.daoHelper.queryRecords(statementId, currentId);
		if (!ListUtil.isNullOrEmpty(records)){
			DataRow firstRow = records.get(records.size()-1);
			String tempMenuId = firstRow.stringValue(columnIdField);
			if (currentId.equals(tempMenuId)){
				result = true;
			}
		}
		return result;
	}
	
	public List<DataRow> queryPickTreeRecords(DataParam param) {
		String statementId = sqlNameSpace+"."+"queryPickTreeRecords";
		List<DataRow> result = this.daoHelper.queryRecords(statementId, param);
		return result;
	}	
	
	public Map<String,String> getTabIdAndColFieldMapping(){
		return tabIdAndColFieldMapping;
	}
	
	public void setTabIdAndTableNameMapping(
			HashMap<String, String> tabIdAndTableNameMapping) {
		this.tabIdAndTableNameMapping = tabIdAndTableNameMapping;
	}

	public void setTabIdAndColFieldMapping(
			Map<String, String> tabIdAndColFieldMapping) {
		this.tabIdAndColFieldMapping = tabIdAndColFieldMapping;
	}
	
	public void setTabIdAndTableModeMapping(
			Map<String, String> tabIdAndTableModeMapping) {
		this.tabIdAndTableModeMapping = tabIdAndTableModeMapping;
	}
}
